/*************************************************************************************
 * Nombre del archivo: Parser.java
 * Universidad del Valle de Guatemala
 * Curso: Diseño de Lenguajes de Programación
 * @author martin
 *          Martín Guzmán 08041
 * Fecha: Mayo de 2010
 * Descripción: tercer proyecto. GENERADOR DE ANALIZADOR SINTÁCTICO. Clase que contiene el Parser
 *          generado para el archivo de entrada utilizando el Scanner (también generado)
*************************************************************************************/

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFileChooser;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Parser {

	final int maxToken = 14;
	public Token LastToken;
	public Token LAToken;
	public int MaxErrors = 5;
	public int CurrentErrors=0;
	public GeneratedScanner Scanner;
	;


	/***********************************************
	* Método: Parser
	* Uso: Constructor
	***********************************************/
	public void Parser(){
		//ver que poner acá...
	}


	/***********************************************
	* Método: Expect
	* Uso: Si el LAToken no contiene el valor pedido, es un error
	* @param n, que es el número de token a esperar
	***********************************************/
	public void Expect(int n){
		if(LAToken.getKind() == n){
			Get();
		}
		else{
			SynError(n);
		}
	}


	/***********************************************
	* Método: Get
	* Uso: Obtiene el siguiente token del Scanner
	***********************************************/
	public void Get(){
		LastToken = LAToken.clone();
		LAToken = Scanner.Scan();
	}


	/***********************************************
	* Método: SynError
	* Uso: Imprime el número de error que se obtuvo
	* @param n, que es el número de token a ver de error
	***********************************************/
	public void SynError(int n){
		//Errors.SynError(LAToken.line, LAToken.col, n);
		System.out.println("Hubo un error, ya que se esperaba token: "+n);
	}


	/***********************************************
	* Método: Parse
	* Uso: Empieza a parsear
	***********************************************/
	public void Parse(GeneratedScanner scan){
		this.Scanner = scan;
		this.LAToken = new Token();
		Get();
		//Expr();
		Expect(-1);
	}


	/***********************************************
	* Método: Expr
	* Uso: Evalua la producción: {Stat";"{white}}{white}"."
	***********************************************/
	public void Expr(){
		
		//Term
		// -> Factor:{Stat";"{white}}
		//{
		while(LAToken.getKind()==8 || LAToken.getKind()==2 || LAToken.getKind()==3 || LAToken.getKind()==11){
		//Term
			// -> Factor:Stat
			Stat();
			// -> Factor:";"
			Expect(5);
			// -> Factor:{white}
			//{
			while(LAToken.getKind()==4){
			//Term
				// -> Factor:white
				Expect(4);
			}
			//}
		}
		//}
		// -> Factor:{white}
		//{
		while(LAToken.getKind()==4){
		//Term
			// -> Factor:white
			Expect(4);
		}
		//}
		// -> Factor:"."
		Expect(6);

		
	}


	/***********************************************
	* Método: Stat
	* Uso: Evalua la producción: (.Double value=new Double(0);.) Expression<.value.> (.System.out.println("Resultado: "+value);.)
	***********************************************/
	public void Stat(){
		
		//Term
		// -> Factor:(.Double value=new Double(0);.)
		Double value=new Double(0);
		// -> Factor:Expression<.value.>
		Expression(value);
		// -> Factor:(.System.out.println("Resultado: "+value);.)
		System.out.println("Resultado: "+value);

		
	}


	/***********************************************
	* Método: Expression
	* Uso: Evalua la producción: (.Double result1= new Double(0),result2= new Double(0);.) Term<.result1.>
	{ "+"Term<.result2.>	(.result1+=result2;.)
	| "-"Term<.result2.>	(.result1-=result2;.)
	} (.result=result1;.)
	***********************************************/
	public void Expression(Double result){
		
		//Term
		// -> Factor:(.Double result1= new Double(0),result2= new Double(0);.)
		Double result1= new Double(0),result2= new Double(0);
		// -> Factor:Term<.result1.>
		Term(result1);
		// -> Factor:{ "+"Term<.result2.>	(.result1+=result2;.)	| "-"Term<.result2.>	(.result1-=result2;.)	} 
		//{
		while(LAToken.getKind()==7 || LAToken.getKind()==8){
			switch(LAToken.getKind()){
				//Term0
				case 7:
										// -> Factor:"+"
					Expect(7);
					// -> Factor:Term<.result2.>
					Term(result2);
					// -> Factor:(.result1+=result2;.)
					result1+=result2;
					break;
				//Term1
				case 8:
										// -> Factor:"-"
					Expect(8);
					// -> Factor:Term<.result2.>
					Term(result2);
					// -> Factor:(.result1-=result2;.)
					result1-=result2;
					break;
			}
		}
		//}
		// -> Factor:(.result=result1;.)
		result=result1;

		
	}


	/***********************************************
	* Método: Term
	* Uso: Evalua la producción: (.Double result1= new Double(0),result2= new Double(0);.)	Factor<.result1.>
	{ "*"Factor<.result2.>	(.result1*=result2;.)
	  | "/"Factor<.result2.> (.result1/=result2;.)
	} (.result=result1;.)
	***********************************************/
	public void Term(Double result){
		
		//Term
		// -> Factor:(.Double result1= new Double(0),result2= new Double(0);.)
		Double result1= new Double(0),result2= new Double(0);
		// -> Factor:Factor<.result1.>
		Factor(result1);
		// -> Factor:{ "*"Factor<.result2.>	(.result1*=result2;.)	  | "/"Factor<.result2.> (.result1/=result2;.)	} 
		//{
		while(LAToken.getKind()==9 || LAToken.getKind()==10){
			switch(LAToken.getKind()){
				//Term0
				case 9:
										// -> Factor:"*"
					Expect(9);
					// -> Factor:Factor<.result2.>
					Factor(result2);
					// -> Factor:(.result1*=result2;.)
					result1*=result2;
					break;
				//Term1
				case 10:
										// -> Factor:"/"
					Expect(10);
					// -> Factor:Factor<.result2.>
					Factor(result2);
					// -> Factor:(.result1/=result2;.)
					result1/=result2;
					break;
			}
		}
		//}
		// -> Factor:(.result=result1;.)
		result=result1;

		
	}


	/***********************************************
	* Método: Factor
	* Uso: Evalua la producción: (.double sign=1;.)	["-"(.sign = -1;.)]
	(Number<.result.> |"("Expression<.result.>")")	(.result*=sign;.)
	***********************************************/
	public void Factor(Double result){
		
		//Term
		// -> Factor:(.double sign=1;.)
		double sign=1;
		// -> Factor:["-"(.sign = -1;.)]	
		//[
		if(LAToken.getKind()==8){
		//Term
			// -> Factor:"-"
			Expect(8);
			// -> Factor:(.sign = -1;.)
			sign = -1;
		}
		//]
		// -> Factor:(Number<.result.> |"("Expression<.result.>")")	
		//(
		if(LAToken.getKind()==2 || LAToken.getKind()==3 || LAToken.getKind()==11){
			switch(LAToken.getKind()){
				//Term0
				case 2:
				case 3:
										// -> Factor:Number<.result.>
					Number(result);
					break;
				//Term1
				case 11:
										// -> Factor:"("
					Expect(11);
					// -> Factor:Expression<.result.>
					Expression(result);
					// -> Factor:")"
					Expect(12);
					break;
			}
		}
		else {
			SynError(-1);
		}
		//)
		// -> Factor:(.result*=sign;.)
		result*=sign;

		
	}


	/***********************************************
	* Método: Number
	* Uso: Evalua la producción: (number | decnumber)(.result = Double.parseDouble(LastToken.value);.)
	***********************************************/
	public void Number(Double result){
		
		//Term
		// -> Factor:(number | decnumber)
		//(
		if(LAToken.getKind()==2 || LAToken.getKind()==3){
			switch(LAToken.getKind()){
				//Term0
				case 2:
										// -> Factor:number
					Expect(2);
					break;
				//Term1
				case 3:
										// -> Factor:decnumber
					Expect(3);
					break;
			}
		}
		else {
			SynError(-1);
		}
		//)
		// -> Factor:(.result = Double.parseDouble(LastToken.value);.)
		result = Double.parseDouble(LastToken.value);

		
	}


}